Triggers: support managing columns for data iteration#7541
Triggers: support managing columns for data iteration#7541labkey-nicka wants to merge 15 commits intodevelopfrom
Conversation
api/src/org/labkey/api/dataiterator/TriggerDataBuilderHelper.java
Outdated
Show resolved
Hide resolved
labkey-matthewb
left a comment
There was a problem hiding this comment.
Considerations for additional features (do we want to do now or never)?
- Support different managed columns for insert/update
- Support in JavaScript triggers
1d28e80 to
3e9e24f
Compare
Implemented both of these. |
7096977 to
5ff3f06
Compare
61286bc to
3e70d27
Compare
| if (errors.hasErrors()) | ||
| break; | ||
|
|
||
| if (trackedRow != null) |
There was a problem hiding this comment.
should we add manageColumns check to this check? if (trackedRow != null && manageColumns)
There was a problem hiding this comment.
No, we want to inform/check for changes regardless of the state of the manageColumns flag.
There was a problem hiding this comment.
I've revised this check to no longer apply to the non-data iterator configuration. We now will only check for managed columns when in a data iterator (and before is true and experimental flag is true). No more logging warnings as encountering this in a data iterator is always considered an error.
labkey-matthewb
left a comment
There was a problem hiding this comment.
I like the error checking, and merging in the values for the managed columns early is an interesting idea that probably greatly reduces the chance of losing data.
labkey-matthewb
left a comment
There was a problem hiding this comment.
One small suggestion. I like the strict error checking.
3e70d27 to
faf395c
Compare
| return; | ||
|
|
||
| if (oldRow == null) | ||
| throw new IllegalArgumentException("An existing record must be supplied for all UPDATE triggers"); |
There was a problem hiding this comment.
What if there are no managed columns, can oldRow be null? It seems the caller all have oldRow as Nullable.
There was a problem hiding this comment.
The term "An existing record" is ambiguous here. oldRow and existingRecord are different.
There was a problem hiding this comment.
I wanted to be consistent in how this is referred to in error messaging, not necessarily with the code name. Intentional.
| */ | ||
| default void setInsertManagedColumns( | ||
| Map<String, Object> newRow, | ||
| @Nullable Map<String, Object> existingRecord, |
There was a problem hiding this comment.
existingRecord doesn't seem actually used, is it meant to be passed in as oldRow? If not, the param could instead be hasExistingRecord for existingRecord == null
There was a problem hiding this comment.
Good catch. I was intending to pass the existingRecord through. Done.
| * @param oldRow The previous row for UPDATE and DELETE | ||
| * @param extraContext Optional additional bindings to set in the script's context when evaluating. | ||
| * @param existingRecord Optional existing record for the row, used for merge operation to differentiate new vs existing row | ||
| * @param manageColumns Whether to manage columns for the row. |
There was a problem hiding this comment.
This param confuses me with the experimental flag, consider renaming?
There was a problem hiding this comment.
I've removed this parameter and now compute manageColumns internally to the method.
- no longer process non-data iterator pathway for managed columns
faf395c to
53e962e
Compare
Rationale
When query triggers are called within data iterators they are allowed to manipulate the data of the row that is being procured. However, if a trigger modifies the columns (i.e., the keys of the row map) it can result in data being mismanaged due to the columns in the row not aligning with what the data iterator specified.
This introduces the notion of "managed" columns to triggers. Triggers can, at the outset, declare which columns they are going to manage. Any managed columns are then picked up by the data iterator during initialization to ensure they are persisted correctly. To enforce this management more strictly, and to avoid mismanagement of null values, triggers are required to fulfill all managed column values by either clearing the value or setting the value. After the trigger has fired the resulting row will be validated and checked. The result is consistent enforcement and acknowledgement of triggers that manipulate the shape of the data.
Related Pull Requests
Changes
TableInfo.getTriggerManagedColumns()to allow for data iterator to gather all managed columnssetInsertManagedColumns()andsetUpdateManagedColumns())Tasks
Manual Testing notes (in progress)